package org.metasketch.editor.toolbox;

import java.util.ArrayList;
import java.util.List;

import javafx.geometry.Point2D;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.shape.Rectangle;
import org.metasketch.diagram.javafx.graphics.BaseGraphic;
import org.metasketch.diagram.javafx.graphics.BaseLink;
import org.metasketch.diagram.javafx.graphics.LineControlPoint;
import org.metasketch.editor.timeline.SnapshotManager;
import org.metasketch.javafx.graphics.JFXDiagram;
import org.metasketch.model.BaseModel;

public class DefaultSelectHandler implements IToolHandler {

	List<ISelectable> selection = new ArrayList<ISelectable>();
	private boolean selectBox;

	Rectangle selectBoxGraphic = new Rectangle(0, 0, 10, 10);
	Point2D dragAnchor;

	boolean moving = false;

	public DefaultSelectHandler() {
		selectBoxGraphic
				.setStyle("-fx-fill: transparent; -fx-stroke: gray;  -fx-stroke-type: outside;  -fx-stroke-width: 5;   -fx-stroke-dash-array: 12 2 4 2;    -fx-stroke-dash-offset: 6;     -fx-stroke-line-cap: butt; -fx-opacity: 0.5;");
	}

	@Override
	public void handle(MouseEvent event, JFXDiagram jfxDiagram, BaseModel model) {

		System.out.println("Select tool: " + event);

		try {

			if (event.getEventType() == MouseEvent.MOUSE_CLICKED
					&& event.getClickCount() == 1
					&& event.getButton() == MouseButton.PRIMARY) {

				if (selectBox) {
					selectBox = false;
					event.consume();
					return;
				}

				if (moving) {
					moving = false;
					event.consume();

					// stopped moving !!!!
					SnapshotManager.takeSnapshot();

					return;
				}

				Object source = event.getSource();
				if (source instanceof BaseGraphic) {

					if (!event.isControlDown())
						deselectAll();

					BaseGraphic sourceGraphic = (BaseGraphic) source;

					if (!selection.contains(sourceGraphic)) {
						selectGraphic(event, sourceGraphic);
					} else {
						sourceGraphic.setSelected(false);
						selection.remove(sourceGraphic);
					}

					event.consume();

				} else if (source instanceof BaseLink) {

					ISelectable sourceGraphic = (ISelectable) source;
					if (!selection.contains(sourceGraphic)) {
						selectGraphic(event, sourceGraphic);
					} else {

						if (event.getTarget() instanceof LineControlPoint) {
							event.consume();
							return;
						}

						sourceGraphic.setSelected(false);
						selection.remove(sourceGraphic);
					}

					// BaseLink baseLink = (BaseLink) source;
					// baseLink.setSelected(true);
					// selection.add(baseLink);

					event.consume();

				} else {

					deselectAll();

					event.consume();
				}

			} else if (event.getEventType() == MouseEvent.MOUSE_PRESSED
					&& event.getButton() == MouseButton.PRIMARY) {

				Object source = event.getSource();
				// if (!(source instanceof BaseGraphic)) {
				// activateSelectBox(event, jfxDiagram);
				// return;
				// }

				if (!selection.contains(source))
					return;

				// BaseGraphic sourceGraphic = (BaseGraphic) source;
				for (ISelectable sourceGraphic : selection) {
					if (sourceGraphic instanceof IDraggable) {
						((IDraggable) sourceGraphic).setInitDragParams(
								event.getSceneX(), event.getSceneY());
					}
				}

				event.consume();

			} else if (event.getEventType() == MouseEvent.MOUSE_DRAGGED
					&& event.getButton() == MouseButton.PRIMARY) {

				Object source = event.getSource();
				if (!(source instanceof BaseGraphic)) {
					if (!selectBox)
						activateSelectBox(event, jfxDiagram);

					updateSelectBox(event);
					return;
				}
				// update bounding box

				if (!selection.contains(source))
					return;

				// BaseGraphic sourceGraphic = (BaseGraphic) source;
				for (ISelectable sourceGraphic : selection) {
					if (sourceGraphic instanceof IDraggable) {
						((IDraggable) sourceGraphic).move(event.getSceneX(),
								event.getSceneY());
					}
				}

				moving = true;

				event.consume();

			} else if (event.getEventType() == MouseEvent.MOUSE_RELEASED
					&& event.getButton() == MouseButton.PRIMARY) {

				// TODO if in select box mode, turn it off and select all
				// contained graphics.
				if (selectBox) {
					applySelectBox(event, jfxDiagram);
					// selectBox = false;
					event.consume();
				} else if (event.getSource() instanceof BaseGraphic) {

					BaseGraphic source = (BaseGraphic) event.getSource();
					if (source.isSelected() && source.isResizing()) {
						source.stopResizing();
						System.err.println("just resized something...");
						SnapshotManager.takeSnapshot();
						event.consume();
					}
				}

			}

		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private void selectGraphic(MouseEvent event, ISelectable sourceGraphic) {
		sourceGraphic.setSelected(true);

		if (sourceGraphic instanceof IDraggable)
			((IDraggable) sourceGraphic).setInitDragParams(event.getSceneX(),
					event.getSceneY());

		selection.add(sourceGraphic);
	}

	private void activateSelectBox(MouseEvent event, JFXDiagram jfxDiagram) {
		selectBox = true;

		selectBoxGraphic.setTranslateX(event.getX());
		selectBoxGraphic.setTranslateY(event.getY());
		selectBoxGraphic.setWidth(5);
		selectBoxGraphic.setHeight(5);

		dragAnchor = new Point2D(event.getX(), event.getY());

		jfxDiagram.addBlindNode(selectBoxGraphic);

	}

	private void updateSelectBox(MouseEvent event) {

		if (event.getX() < dragAnchor.getX()) {
			selectBoxGraphic.setTranslateX(event.getX());
			selectBoxGraphic.setWidth(dragAnchor.getX() - event.getX());
		} else {
			selectBoxGraphic.setWidth(event.getX() - dragAnchor.getX());
		}

		if (event.getY() < dragAnchor.getY()) {
			selectBoxGraphic.setTranslateY(event.getY());
			selectBoxGraphic.setHeight(dragAnchor.getY() - event.getY());
		} else {
			selectBoxGraphic.setHeight(event.getY() - dragAnchor.getY());
		}

	}

	private void applySelectBox(MouseEvent event, JFXDiagram jfxDiagram) {
		jfxDiagram.removeNode(selectBoxGraphic);

		if (!event.isControlDown())
			deselectAll();

		List<BaseGraphic> selectedNodes = jfxDiagram.getNodesAt(
				selectBoxGraphic.getTranslateX(),
				selectBoxGraphic.getTranslateY(), selectBoxGraphic.getWidth(),
				selectBoxGraphic.getHeight());
		for (BaseGraphic baseGraphic : selectedNodes) {
			selectGraphic(event, baseGraphic);
		}

	}

	private void deselectAll() {
		for (ISelectable graphic : selection) {
			graphic.setSelected(false);
		}
		selection.clear();
	}

	@Override
	public void cleanup() {
		// TODO Auto-generated method stub

	}

}
